package com.teamsun.filter;

import com.teamsun.cache.CacheManager;
import com.teamsun.rptcfg.BaseRpt;
import com.teamsun.service.ISaveRptService;
import com.teamsun.util.Base64Util;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * <p>报表工具全局Filter,用于权限控制</p>
 * <p>如果其他系统接入报表工具需要做权限控制时，目前报表工具提供的解决方案为:</p>
 * <p>报表工具对接入系统提供Token,其他系统访问报表时需要将该Token传递给报表工具</p>
 * <p>报表工具根据传入的Token判断该Token值是否正确,如果正确则允许访问报表</p>
 */
public class RptFilter implements Filter {
    @Autowired
    private ISaveRptService saveRptService;

    @Autowired
    private CacheManager cacheManager;

    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        HttpServletResponse response = (HttpServletResponse) resp;
        HttpServletRequest request = (HttpServletRequest) req;

        // 设置可以跨域访问
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Headers","User-Agent,Origin,Cache-Control,Content-type,Date,Server,withCredentials,AccessToken");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
        response.setHeader("Access-Control-Expose-Headers", "accesstoken");
        response.setHeader("Access-Control-Request-Headers", "accesstoken");
        response.setHeader("Expires", "-1");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("pragma", "no-cache");

        // 如果其他系统访问报表工具时需要添加权限控制，则需要验证Token
        // 获取报表ID
        String rptId = request.getParameter("rptId");
        String referer = request.getHeader("referer");

        // todo 部分客户浏览器取不到referer，暂不做防盗链
        referer = "referer";

        try {
            // 前台对参数做了2次加密,后台需做2次解密
            rptId = Base64Util.decodeToString(rptId);
            rptId = Base64Util.decodeToString(rptId);
            rptId = rptId.substring(0, rptId.length() - 6);
        } catch (Exception e) {
            request.getRequestDispatcher("/pages/error.jsp").forward(request, response);
        }
        // 报表信息不再缓存中，则需要从数据库中查询
        BaseRpt baseRpt = null;
        Object rptObj = cacheManager.getRptCache(rptId);
        if(rptObj != null) {
            baseRpt = (BaseRpt) rptObj;
        } else {
            baseRpt = saveRptService.queryRptCfgById(rptId);
        }
        if(baseRpt != null) {
            String rptToken = baseRpt.getRptToken();
            String accessIn = baseRpt.getAccessSysCode();

            // 如果请求头中的referer为空，则说明报表是直接通过报表链接访问
            // 如果报表配置了接入系统，则拦截访问请求，用户必须通过接入系统访问报表
            if(StringUtils.isNotBlank(accessIn)) {
                if(referer == null) {
                    request.setAttribute("errorMsg", "您无权访问该报表&nbsp;请先登录");
                    request.getRequestDispatcher("/pages/error.jsp").forward(request, response);
                }
            }
            if(StringUtils.isNotBlank(rptToken)) {
                String tokenParma = request.getParameter("token");
                if(!rptToken.equals(tokenParma)) {
                    request.setAttribute("errorMsg", "您无权访问该报表");
                    request.getRequestDispatcher("/pages/error.jsp").forward(request, response);
                }
            }
        } else {
            request.getRequestDispatcher("/pages/error.jsp").forward(request, response);
        }
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {
        // 在Filter中可使用spring注解进行Bean的注入
        SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, config.getServletContext());
    }

}
